/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/


//============================================================================
/// \file   DockAreaTitleBar.cpp
/// \author Uwe Kindler
/// \date   12.10.2018
/// \brief  Implementation of CDockAreaTitleBar class
//============================================================================

//============================================================================
//                                   INCLUDES
//============================================================================
#include "DockAreaTitleBar.h"

#include <QPushButton>
#include <QToolButton>
#include <QBoxLayout>
#include <QStyle>
#include <QMenu>
#include <QScrollArea>
#include <QMouseEvent>
#include <QDebug>
#include <QPointer>
#include <QApplication>

#include "DockAreaTitleBar_p.h"
#include "ads_globals.h"
#include "FloatingDockContainer.h"
#include "FloatingDragPreview.h"
#include "DockAreaWidget.h"
#include "DockOverlay.h"
#include "DockManager.h"
#include "DockWidget.h"
#include "DockWidgetTab.h"
#include "DockAreaTabBar.h"
#include "DockComponentsFactory.h"
#include "DockFocusController.h"
#include "ElidingLabel.h"
#include "AutoHideDockContainer.h"
#include "IconProvider.h"

#include <iostream>

namespace ads
{
static const char* const LocationProperty = "Location";

/**  
 * 私有数据类的CDockAreaTitleBar类（pimpl） 
 */ 
struct DockAreaTitleBarPrivate 
{ 
    CDockAreaTitleBar* _this; 
    QPointer<CTitleBarButton> TabsMenuButton; 
    QPointer<CTitleBarButton> AutoHideButton; 
    QPointer<CTitleBarButton> UndockButton; 
    QPointer<CTitleBarButton> CloseButton; 
    QBoxLayout* Layout; 
    CDockAreaWidget* DockArea; 
    CDockAreaTabBar* TabBar; 
    CElidingLabel* AutoHideTitleLabel; 
    bool MenuOutdated = true; 
    QMenu* TabsMenu; 
    QList<tTitleBarButton*> DockWidgetActionsButtons; 
    QPoint DragStartMousePos; 
    eDragState DragState = DraggingInactive; 
    IFloatingWidget* FloatingWidget = nullptr; 
 
    /** 
     * 私有数据构造函数 
     */ 
    DockAreaTitleBarPrivate(CDockAreaTitleBar* _public); 
 
    /** 
     * 创建标题栏的关闭和菜单按钮 
     */ 
    void createButtons(); 
 
    /** 
     * 创建自动隐藏标题标签，在停靠区域叠加时显示 
     */ 
    void createAutoHideTitleLabel(); 
 
    /** 
     * 创建内部TabBar 
     */ 
    void createTabBar(); 
 
    /** 
     * 方便访问DockManager的函数 
     */ 
    CDockManager* dockManager() const 
    { 
        return DockArea->dockManager(); 
    } 
 
    /** 
     * 如果给定的配置标志已设置，则返回true 
     * 方便测试配置标志 
     */ 
    static bool testConfigFlag(CDockManager::eConfigFlag Flag) 
    { 
        return CDockManager::testConfigFlag(Flag); 
    } 
 
    /** 
     * 如果给定的配置标志已设置，则返回true 
     * 方便测试配置标志 
     */ 
    static bool testAutoHideConfigFlag(CDockManager::eAutoHideFlag Flag) 
    { 
        return CDockManager::testAutoHideConfigFlag(Flag); 
    } 
 
    /** 
     * 当前拖动状态的测试函数 
     */ 
    bool isDraggingState(eDragState dragState) const 
    { 
        return this->DragState == dragState; 
    } 
 
    /** 
     * 开始浮动 
     */ 
    void startFloating(const QPoint& Offset); 
 
    /** 
     * 使停靠区域浮动 
     */ 
    IFloatingWidget* makeAreaFloating(const QPoint& Offset, eDragState DragState); 
 
    /** 
     * 创建和初始化“自动隐藏到...”菜单的菜单项的辅助函数 
     */ 
    QAction* createAutoHideToAction(const QString& Title, SideBarLocation Location, QMenu* Menu) 
    { 
        auto Action = Menu->addAction(Title); 
        Action->setProperty("Location", Location); 
        QObject::connect(Action, &QAction::triggered, _this, &CDockAreaTitleBar::onAutoHideToActionClicked); 
        return Action; 
    } 
}; 
 
DockAreaTitleBarPrivate::DockAreaTitleBarPrivate(CDockAreaTitleBar* _public) : 
    _this(_public) 
{ 
} 
 
void DockAreaTitleBarPrivate::createButtons() 
{ 
    QSizePolicy ButtonSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); 
 
    // Tabs menu button 
    TabsMenuButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasTabsMenuButton)); 
    TabsMenuButton->setObjectName("tabsMenuButton"); 
    TabsMenuButton->setAutoRaise(true); 
    TabsMenuButton->setPopupMode(QToolButton::InstantPopup); 
    internal::setButtonIcon(TabsMenuButton, QStyle::SP_TitleBarUnshadeButton, ads::DockAreaMenuIcon); 
    QMenu* TabsMenu = new QMenu(TabsMenuButton); 
#ifndef QT_NO_TOOLTIP 
    TabsMenu->setToolTipsVisible(true); 
#endif 
    _this->connect(TabsMenu, SIGNAL(aboutToShow()), SLOT(onTabsMenuAboutToShow())); 
    TabsMenuButton->setMenu(TabsMenu); 
    internal::setToolTip(TabsMenuButton, QObject::tr("List All Tabs")); 
    TabsMenuButton->setSizePolicy(ButtonSizePolicy); 
    Layout->addWidget(TabsMenuButton, 0); 
    _this->connect(TabsMenuButton->menu(), SIGNAL(triggered(QAction*)), SLOT(onTabsMenuActionTriggered(QAction*))); 
 
    // Undock button 
    UndockButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasUndockButton)); 
    UndockButton->setObjectName("detachGroupButton"); 
    UndockButton->setAutoRaise(true); 
    internal::setToolTip(UndockButton, QObject::tr("Detach Group")); 
    internal::setButtonIcon(UndockButton, QStyle::SP_TitleBarNormalButton, ads::DockAreaUndockIcon); 
    UndockButton->setSizePolicy(ButtonSizePolicy); 
    Layout->addWidget(UndockButton, 0); 
    _this->connect(UndockButton, SIGNAL(clicked()), SLOT(onUndockButtonClicked())); 
 
    // AutoHide Button 
    const auto autoHideEnabled = testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled); 
    AutoHideButton = new CTitleBarButton(testAutoHideConfigFlag(CDockManager::DockAreaHasAutoHideButton) && autoHideEnabled); 
    AutoHideButton->setObjectName("dockAreaAutoHideButton"); 
    AutoHideButton->setAutoRaise(true); 
    internal::setToolTip(AutoHideButton, _this->titleBarButtonToolTip(TitleBarButtonAutoHide)); 
    internal::setButtonIcon(AutoHideButton, QStyle::SP_DialogOkButton, ads::AutoHideIcon); 
    AutoHideButton->setSizePolicy(ButtonSizePolicy); 
    AutoHideButton->setCheckable(testAutoHideConfigFlag(CDockManager::AutoHideButtonCheckable)); 
    AutoHideButton->setChecked(false); 
    Layout->addWidget(AutoHideButton, 0); 
    _this->connect(AutoHideButton, SIGNAL(clicked()), SLOT(onAutoHideButtonClicked())); 
 
    // Close button 
    CloseButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasCloseButton)); 
    CloseButton->setObjectName("dockAreaCloseButton"); 
    CloseButton->setAutoRaise(true); 
    internal::setButtonIcon(CloseButton, QStyle::SP_TitleBarCloseButton, ads::DockAreaCloseIcon); 
    internal::setToolTip(CloseButton, _this->titleBarButtonToolTip(TitleBarButtonClose)); 
    CloseButton->setSizePolicy(ButtonSizePolicy); 
    CloseButton->setIconSize(QSize(16, 16)); 
    Layout->addWidget(CloseButton, 0); 
    _this->connect(CloseButton, SIGNAL(clicked()), SLOT(onCloseButtonClicked())); 
} 
 
void DockAreaTitleBarPrivate::createAutoHideTitleLabel() 
{ 
    AutoHideTitleLabel = new CElidingLabel(""); 
    AutoHideTitleLabel->setObjectName("autoHideTitleLabel"); 
    Layout->addWidget(AutoHideTitleLabel); 
} 
 
void DockAreaTitleBarPrivate::createTabBar() 
{ 
    TabBar = componentsFactory()->createDockAreaTabBar(DockArea); 
    TabBar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); 
    Layout->addWidget(TabBar); 
    _this->connect(TabBar, SIGNAL(tabClosed(int)), SLOT(markTabsMenuOutdated())); 
    _this->connect(TabBar, SIGNAL(tabOpened(int)), SLOT(markTabsMenuOutdated())); 
    _this->connect(TabBar, SIGNAL(tabInserted(int)), SLOT(markTabsMenuOutdated())); 
    _this->connect(TabBar, SIGNAL(removingTab(int)), SLOT(markTabsMenuOutdated())); 
    _this->connect(TabBar, SIGNAL(tabMoved(int, int)), SLOT(markTabsMenuOutdated())); 
    _this->connect(TabBar, SIGNAL(currentChanged(int)), SLOT(onCurrentTabChanged(int))); 
    _this->connect(TabBar, SIGNAL(tabBarClicked(int)), SIGNAL(tabBarClicked(int))); 
    _this->connect(TabBar, SIGNAL(elidedChanged(bool)), SLOT(markTabsMenuOutdated())); 
}


//============================================================================
// 函数: makeAreaFloating
// 描述: 将停靠区域转为浮动窗口，并返回浮动窗口部件
// 参数:
// - Offset: 浮动窗口的偏移位置
// - DragState: 浮动窗口的拖动状态
// 返回值: 浮动窗口部件
//============================================================================
IFloatingWidget* DockAreaTitleBarPrivate::makeAreaFloating(const QPoint& Offset, eDragState DragState)
{
    QSize Size = DockArea->size();
    this->DragState = DragState;
    bool CreateFloatingDockContainer = (DraggingFloatingWidget != DragState);
    CFloatingDockContainer* FloatingDockContainer = nullptr;
    IFloatingWidget* FloatingWidget;

    if (CreateFloatingDockContainer)
    {
        // 清理和删除自动隐藏停靠容器（如果存在）
        if (DockArea->autoHideDockContainer())
        {
            DockArea->autoHideDockContainer()->cleanupAndDelete();
        }
        FloatingWidget = FloatingDockContainer = new CFloatingDockContainer(DockArea);
    }
    else
    {
        auto w = new CFloatingDragPreview(DockArea);
        // 将 draggingCanceled 信号连接到设置 DragState 为 DraggingInactive 的槽函数
        QObject::connect(w, &CFloatingDragPreview::draggingCanceled, [=]()
        {
            this->DragState = DraggingInactive;
        });
        FloatingWidget = w;
    }

    // 开始浮动部件
    FloatingWidget->startFloating(Offset, Size, DragState, nullptr);

    if (FloatingDockContainer)
    {
        // 如果顶级停靠窗口存在，则发射 topLevelChanged 信号
        auto TopLevelDockWidget = FloatingDockContainer->topLevelDockWidget();
        if (TopLevelDockWidget)
        {
            TopLevelDockWidget->emitTopLevelChanged(true);
        }
    }

    return FloatingWidget;
}

//============================================================================
// 函数: startFloating
// 描述: 开始浮动停靠区域
// 参数:
// - Offset: 浮动窗口的偏移位置
//============================================================================
void DockAreaTitleBarPrivate::startFloating(const QPoint& Offset)
{
    // 如果自动隐藏停靠容器存在，则隐藏它
    if (DockArea->autoHideDockContainer())
    {
        DockArea->autoHideDockContainer()->hide();
    }

    // 将停靠区域转为浮动窗口
    FloatingWidget = makeAreaFloating(Offset, DraggingFloatingWidget);

    // 将 dockedWidgetDragStartEvent 事件发送给停靠区域
    qApp->postEvent(DockArea, new QEvent((QEvent::Type)internal::DockedWidgetDragStartEvent));
}

//============================================================================
// 构造函数: CDockAreaTitleBar
// 描述: 初始化停靠区域标题栏
// 参数:
// - parent: 父级停靠区域部件
//============================================================================
CDockAreaTitleBar::CDockAreaTitleBar(CDockAreaWidget* parent) :
    QFrame(parent),
    d(new DockAreaTitleBarPrivate(this))
{
    d->DockArea = parent;
    setObjectName("dockAreaTitleBar");

    // 创建并设置布局
    d->Layout = new QBoxLayout(QBoxLayout::LeftToRight);
    d->Layout->setContentsMargins(0, 0, 0, 0);
    d->Layout->setSpacing(0);
    setLayout(d->Layout);

    setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);

    // 创建选项卡栏和自动隐藏标题标签
    d->createTabBar();
    d->createAutoHideTitleLabel();
    d->AutoHideTitleLabel->setVisible(false); // 默认隐藏

    // 添加间隔部件到布局中
    d->Layout->addWidget(new CSpacerWidget(this));

    // 创建按钮
    d->createButtons();

    // 设置焦点策略为 NoFocus
    setFocusPolicy(Qt::NoFocus);
}

//============================================================================
// 析构函数: ~CDockAreaTitleBar
// 描述: 销毁停靠区域标题栏
//============================================================================
CDockAreaTitleBar::~CDockAreaTitleBar()
{
    if (!d->CloseButton.isNull())
    {
        delete d->CloseButton;
    }
    if (!d->TabsMenuButton.isNull())
    {
        delete d->TabsMenuButton;
    }
    if (!d->UndockButton.isNull())
    {
        delete d->UndockButton;
    }
    delete d;
}

//============================================================================
// 函数: tabBar
// 描述: 返回停靠区域标题栏的选项卡栏
// 返回值: 选项卡栏
//============================================================================
CDockAreaTabBar* CDockAreaTitleBar::tabBar() const
{
    return d->TabBar;
}

//============================================================================
// 函数: markTabsMenuOutdated
// 描述: 标记选项卡菜单已过时，并更新其可见性
//============================================================================
void CDockAreaTitleBar::markTabsMenuOutdated()
{
    if(DockAreaTitleBarPrivate::testConfigFlag(CDockManager::DockAreaDynamicTabsMenuButtonVisibility))
    {
        bool hasElidedTabTitle = false;

        // 检查是否有选项卡标题被省略
        for (int i = 0; i < d->TabBar->count(); ++i)
        {
            if (!d->TabBar->isTabOpen(i))
            {
                continue;
            }
            CDockWidgetTab* Tab = d->TabBar->tab(i);
            if(Tab->isTitleElided())
            {
                hasElidedTabTitle = true;
                break;
            }
        }

        // 根据是否有选项卡标题被省略和选项卡数量决定菜单的可见性
        bool visible = (hasElidedTabTitle && (d->TabBar->count() > 1));
        QMetaObject::invokeMethod(d->TabsMenuButton, "setVisible", Qt::QueuedConnection, Q_ARG(bool, visible));
    }

    d->MenuOutdated = true;
}

//============================================================================
// 函数: onTabsMenuAboutToShow
// 描述: 当选项卡菜单即将显示时更新选项卡菜单
//============================================================================
void CDockAreaTitleBar::onTabsMenuAboutToShow()
{
    if (!d->MenuOutdated)
    {
        return;
    }

    QMenu* menu = d->TabsMenuButton->menu();
    menu->clear();

    // 将选项卡添加到菜单中
    for (int i = 0; i < d->TabBar->count(); ++i)
    {
        if (!d->TabBar->isTabOpen(i))
        {
            continue;
        }

        auto Tab = d->TabBar->tab(i);
        QAction* Action = menu->addAction(Tab->icon(), Tab->text());
        internal::setToolTip(Action, Tab->toolTip());
        Action->setData(i);
    }

    d->MenuOutdated = false;
}


//============================================================================
// CDockAreaTitleBar::onCloseButtonClicked
// 关闭按钮被点击时的处理函数
//============================================================================
void CDockAreaTitleBar::onCloseButtonClicked()
{
    ADS_PRINT("CDockAreaTitleBar::onCloseButtonClicked");

    // 检查是否启用了自动隐藏功能，并且当前区域是自动隐藏的
    if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideCloseButtonCollapsesDock) &&
        d->DockArea->autoHideDockContainer())
    {
        // 折叠自动隐藏的区域
        d->DockArea->autoHideDockContainer()->collapseView(true);
    }
    // 检查是否启用了关闭按钮关闭选项卡的功能
    else if (d->testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab))
    {
        // 关闭当前选项卡
        d->TabBar->closeTab(d->TabBar->currentIndex());
    }
    else
    {
        // 关闭当前区域
        d->DockArea->closeArea();
    }
}

//============================================================================
// CDockAreaTitleBar::onUndockButtonClicked
// 取消停靠按钮被点击时的处理函数
//============================================================================
void CDockAreaTitleBar::onUndockButtonClicked()
{
    // 检查是否支持浮动功能
    if (d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable))
    {
        // 将区域设置为浮动状态
        d->makeAreaFloating(mapFromGlobal(QCursor::pos()), DraggingInactive);
    }
}

//============================================================================
// CDockAreaTitleBar::onTabsMenuActionTriggered
// 选项卡菜单动作被触发时的处理函数
//============================================================================
void CDockAreaTitleBar::onTabsMenuActionTriggered(QAction* Action)
{
    // 获取触发动作对应的选项卡索引
    int Index = Action->data().toInt();
    // 设置当前选项卡为指定索引
    d->TabBar->setCurrentIndex(Index);
    // 发送选项卡被点击的信号
    Q_EMIT tabBarClicked(Index);
}

//============================================================================
// CDockAreaTitleBar::updateDockWidgetActionsButtons
// 更新区域内部窗口的动作按钮
//============================================================================
void CDockAreaTitleBar::updateDockWidgetActionsButtons()
{
    auto Tab = d->TabBar->currentTab();
    if (!Tab)
    {
        return;
    }
    CDockWidget* DockWidget = Tab->dockWidget();
    if (!d->DockWidgetActionsButtons.isEmpty())
    {
        for (auto Button : d->DockWidgetActionsButtons)
        {
            d->Layout->removeWidget(Button);
            delete Button;
        }
        d->DockWidgetActionsButtons.clear();
    }
    auto Actions = DockWidget->titleBarActions();
    if (Actions.isEmpty())
    {
        return;
    }
    int InsertIndex = indexOf(d->TabsMenuButton);
    for (auto Action : Actions)
    {
        auto Button = new CTitleBarButton(true, this);
        Button->setDefaultAction(Action);
        Button->setAutoRaise(true);
        Button->setPopupMode(QToolButton::InstantPopup);
        Button->setObjectName(Action->objectName());
        d->Layout->insertWidget(InsertIndex++, Button, 0);
        d->DockWidgetActionsButtons.append(Button);
    }
}

//============================================================================
// CDockAreaTitleBar::onCurrentTabChanged
// 当前选项卡发生变化时的处理函数
//============================================================================
void CDockAreaTitleBar::onCurrentTabChanged(int Index)
{
    if (Index < 0)
    {
        return;
    }
    if (d->testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab))
    {
        CDockWidget* DockWidget = d->TabBar->tab(Index)->dockWidget();
        d->CloseButton->setEnabled(DockWidget->features().testFlag(CDockWidget::DockWidgetClosable));
    }
    updateDockWidgetActionsButtons();
}

//============================================================================
// CDockAreaTitleBar::onAutoHideButtonClicked
// 自动隐藏按钮被点击时的处理函数
//============================================================================
void CDockAreaTitleBar::onAutoHideButtonClicked()
{
    // 检查是否启用了自动隐藏按钮切换区域的功能，或者按下了Ctrl键
    if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideButtonTogglesArea)
     || qApp->keyboardModifiers().testFlag(Qt::ControlModifier))
    {
        // 切换自动隐藏区域的显示状态
        d->DockArea->toggleAutoHide();
    }
    else
    {
        // 切换当前窗口的自动隐藏状态
        d->DockArea->currentDockWidget()->toggleAutoHide();
    }
}

//============================================================================
// CDockAreaTitleBar::onAutoHideDockAreaActionClicked
// 自动隐藏区域菜单动作被点击时的处理函数
//============================================================================
void CDockAreaTitleBar::onAutoHideDockAreaActionClicked()
{
    // 切换自动隐藏区域的显示状态
    d->DockArea->toggleAutoHide();
}

//============================================================================
// CDockAreaTitleBar::onAutoHideToActionClicked
// 自动隐藏到指定位置菜单动作被点击时的处理函数
//============================================================================
void CDockAreaTitleBar::onAutoHideToActionClicked()
{
    // 获取发送者的位置属性值
    int Location = sender()->property(LocationProperty).toInt();
    // 切换自动隐藏区域的显示状态到指定位置
    d->DockArea->toggleAutoHide((SideBarLocation)Location);
}

//============================================================================
// CDockAreaTitleBar::button
// 获取指定类型的按钮
//============================================================================
CTitleBarButton* CDockAreaTitleBar::button(TitleBarButton which) const
{
    switch (which)
    {
    case TitleBarButtonTabsMenu: return d->TabsMenuButton;
    case TitleBarButtonUndock: return d->UndockButton;
    case TitleBarButtonClose: return d->CloseButton;
    case TitleBarButtonAutoHide: return d->AutoHideButton;
    default:
        return nullptr;
    }
}

//============================================================================
// CDockAreaTitleBar::autoHideTitleLabel
// 获取自动隐藏标题标签
//============================================================================
CElidingLabel* CDockAreaTitleBar::autoHideTitleLabel() const
{
    return d->AutoHideTitleLabel;
}

//============================================================================
// CDockAreaTitleBar::setVisible
// 设置区域标题栏的可见性
//============================================================================
void CDockAreaTitleBar::setVisible(bool Visible)
{
    Super::setVisible(Visible);
    markTabsMenuOutdated();
}

//============================================================================
// CDockAreaTitleBar::mousePressEvent
// 鼠标按下事件处理函数
//============================================================================
void CDockAreaTitleBar::mousePressEvent(QMouseEvent* ev)
{
    if (ev->button() == Qt::LeftButton)
    {
        ev->accept();
        d->DragStartMousePos = ev->pos();
        d->DragState = DraggingMousePressed;
        if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting))
        {
            d->dockManager()->dockFocusController()->setDockWidgetTabFocused(d->TabBar->currentTab());
        }
        return;
    }
    Super::mousePressEvent(ev);
}

//============================================================================
// CDockAreaTitleBar::mouseReleaseEvent
// 鼠标释放事件处理函数
//============================================================================
void CDockAreaTitleBar::mouseReleaseEvent(QMouseEvent* ev)
{
    if (ev->button() == Qt::LeftButton)
    {
        ADS_PRINT("CDockAreaTitleBar::mouseReleaseEvent");
        ev->accept();
        auto CurrentDragState = d->DragState;
        d->DragStartMousePos = QPoint();
        d->DragState = DraggingInactive;
        if (DraggingFloatingWidget == CurrentDragState)
        {
            d->FloatingWidget->finishDragging();
        }
        return;
    }
    Super::mouseReleaseEvent(ev);
}


//============================================================================
void CDockAreaTitleBar::mouseMoveEvent(QMouseEvent* ev)
{
    Super::mouseMoveEvent(ev);
    if (!(ev->buttons() & Qt::LeftButton) || d->isDraggingState(DraggingInactive))
    {
        d->DragState = DraggingInactive;
        return;
    }
    // 移动浮动窗口
    if (d->isDraggingState(DraggingFloatingWidget))
    {
        d->FloatingWidget->moveFloating();
        return;
    }
    // 如果这是浮动停靠容器中的最后一个停靠区域，则没有意义将其移动到新的浮动窗口并将此窗口留空
    if (d->DockArea->dockContainer()->isFloating()
     && d->DockArea->dockContainer()->visibleDockAreaCount() == 1 
     && !d->DockArea->isAutoHide())
    {
        return;
    }
    // 如果此区域中的任何一个停靠窗口不可浮动，则整个区域都不可浮动
    // 如果停靠窗口可移动，则可以创建浮动拖动预览
    auto Features = d->DockArea->features();
    if (!Features.testFlag(CDockWidget::DockWidgetFloatable) && !(Features.testFlag(CDockWidget::DockWidgetMovable)))
    {
        return;
    }
    int DragDistance = (d->DragStartMousePos - ev->pos()).manhattanLength();
    if (DragDistance >= CDockManager::startDragDistance())
    {
        ADS_PRINT("CDockAreaTitleBar::startFloating");
        d->startFloating(d->DragStartMousePos);
        auto Overlay = d->DockArea->dockManager()->containerOverlay();
        Overlay->setAllowedAreas(OuterDockAreas);
    }
    return;
}
//============================================================================
void CDockAreaTitleBar::mouseDoubleClickEvent(QMouseEvent *event)
{
    // 如果这是浮动停靠容器中的最后一个停靠区域，则没有意义将其移动到新的浮动窗口并将此窗口留空
    if (d->DockArea->dockContainer()->isFloating() && d->DockArea->dockContainer()->dockAreaCount() == 1)
    {
        return;
    }
    if (!d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable))
    {
        return;
    }
    d->makeAreaFloating(event->pos(), DraggingInactive);
}
//============================================================================
void CDockAreaTitleBar::setAreaFloating()
{
    // 如果这是浮动停靠容器中的最后一个停靠区域，则没有意义将其移动到新的浮动窗口并将此窗口留空
    auto DockContainer = d->DockArea->dockContainer();
    if (DockContainer->isFloating() && DockContainer->dockAreaCount() == 1
     && !d->DockArea->isAutoHide())
    {
        return;
    }
    if (!d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable))
    {
        return;
    }
    d->makeAreaFloating(mapFromGlobal(QCursor::pos()), DraggingInactive);
}
//============================================================================
void CDockAreaTitleBar::contextMenuEvent(QContextMenuEvent* ev)
{
    ev->accept();
    if (d->isDraggingState(DraggingFloatingWidget))
    {
        return;
    }
    const bool isAutoHide = d->DockArea->isAutoHide();
    const bool isTopLevelArea = d->DockArea->isTopLevelArea();
    QAction* Action;
    QMenu Menu(this);
    if (!isTopLevelArea)
    {
        Action = Menu.addAction(isAutoHide ? tr("Detach") : tr("Detach Group"),
            this, SLOT(onUndockButtonClicked()));
        Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable));
        if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled))
        {
            Action = Menu.addAction(isAutoHide ? tr("Unpin (Dock)") : tr("Pin Group"), this, SLOT(onAutoHideDockAreaActionClicked()));
            auto AreaIsPinnable = d->DockArea->features().testFlag(CDockWidget::DockWidgetPinnable);
            Action->setEnabled(AreaIsPinnable);
            if (!isAutoHide)
            {
                auto menu = Menu.addMenu(tr("Pin Group To..."));
                menu->setEnabled(AreaIsPinnable);
                d->createAutoHideToAction(tr("Top"), SideBarTop, menu);
                d->createAutoHideToAction(tr("Left"), SideBarLeft, menu);
                d->createAutoHideToAction(tr("Right"), SideBarRight, menu);
                d->createAutoHideToAction(tr("Bottom"), SideBarBottom, menu);
            }
        }
        Menu.addSeparator();
    }
    Action = Menu.addAction(isAutoHide ? tr("Close") : tr("Close Group"), this, SLOT(onCloseButtonClicked()));
    Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetClosable));
    if (!isAutoHide && !isTopLevelArea)
    {
        Action = Menu.addAction(tr("Close Other Groups"), d->DockArea, SLOT(closeOtherAreas()));
    }
    Menu.exec(ev->globalPos());
}
//============================================================================
void CDockAreaTitleBar::insertWidget(int index, QWidget *widget)
{
    d->Layout->insertWidget(index, widget);
}
//============================================================================
int CDockAreaTitleBar::indexOf(QWidget *widget) const
{
    return d->Layout->indexOf(widget);
}
//============================================================================
QString CDockAreaTitleBar::titleBarButtonToolTip(TitleBarButton Button) const
{
    switch (Button)
    {
    case TitleBarButtonAutoHide:
         if (d->DockArea->isAutoHide())
         {
             return tr("Unpin (Dock)");
         }
         if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideButtonTogglesArea))
         {
             return tr("Pin Group");
         }
         else
         {
             return tr("Pin Active Tab (Press Ctrl to Pin Group)");
         }
         break;
    case TitleBarButtonClose:
        if (d->DockArea->isAutoHide())
        {
            return tr("Close");
        }
        if (CDockManager::testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab))
        {
            return tr("Close Active Tab");
        }
        else
        {
            return tr("Close Group");
        }
        break;
    default:
        break;
    }
    return QString();
}
//============================================================================
CTitleBarButton::CTitleBarButton(bool showInTitleBar, QWidget* parent)
    : tTitleBarButton(parent),
      ShowInTitleBar(showInTitleBar),
      HideWhenDisabled(CDockManager::testConfigFlag(CDockManager::DockAreaHideDisabledButtons))
{
    setFocusPolicy(Qt::NoFocus);
}
//============================================================================
void CTitleBarButton::setVisible(bool visible)
{
    // 'visible' 只有在此按钮配置为在标题栏中显示时才保持为 'true'：
    visible = visible && this->ShowInTitleBar;
    // 'visible' 只有在此按钮配置为在禁用时不可见且当前处于禁用状态时才保持为 'true'：
    if (visible && HideWhenDisabled)
    {
        visible = isEnabled();
    }
    Super::setVisible(visible);
}
//============================================================================
void CTitleBarButton::setShowInTitleBar(bool Show)
{
    this->ShowInTitleBar = Show;
    if (!Show)
    {
        setVisible(false);
    }
}
//============================================================================
bool CTitleBarButton::event(QEvent *ev)
{
    if (QEvent::EnabledChange == ev->type() && HideWhenDisabled)
    {
        // 强制调用 setVisible()
        // 直接在此处调用 setVisible() 并不适用于首次显示按钮的情况
        QMetaObject::invokeMethod(this, "setVisible", Qt::QueuedConnection, Q_ARG(bool, isEnabled()));
    }
    return Super::event(ev);
}
//============================================================================
CSpacerWidget::CSpacerWidget(QWidget* Parent /*= 0*/) : Super(Parent)
{
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    setStyleSheet("border: none; background: none;");
}

} // namespace ads

//---------------------------------------------------------------------------
// EOF DockAreaTitleBar.cpp
